package com.jixiang.order.service.impl;

import cn.hutool.core.lang.UUID;
import com.jixiang.model.goods.dtos.CartDtos;
import com.jixiang.model.order.dtos.OrderDtos;
import com.jixiang.model.order.entity.OsOrderInfo;
import com.jixiang.model.order.entity.OsOrderValue;
import com.jixiang.order.service.OrderCreateService;
import com.jixiang.order.service.OsOrderInfoService;
import com.jixiang.order.service.OsOrderValueService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFutureCallback;

import javax.annotation.Resource;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.jixiang.common.constants.CodeMqConstants.*;
import static com.jixiang.common.constants.OrderConstants.*;
import static com.jixiang.common.constants.RedisConstants.*;

@Slf4j
@Component
public class OrderCreateImpl implements OrderCreateService {

    @Resource
    private OsOrderInfoService osOrderInfoService;

    @Resource
    private OsOrderValueService osOrderValueService;

    @Autowired
    RabbitTemplate rabbitTemplate;

    private static final DefaultRedisScript<Long> UPDATEORDER_SCRIPT;

    static {
        UPDATEORDER_SCRIPT = new DefaultRedisScript<>();
        UPDATEORDER_SCRIPT.setLocation(new ClassPathResource("updategoods.lua"));
        UPDATEORDER_SCRIPT.setResultType(Long.class);
    }
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Override
    @Async("orderExecutor")
    public void createOrder(OrderDtos orderDtos) {
        OsOrderInfo osOrderInfo = new OsOrderInfo();
        osOrderInfo.setId(orderDtos.getOrderId());
        osOrderInfo.setOrderType(orderDtos.getSelectType());
        osOrderInfo.setUserId(orderDtos.getUserId());
        osOrderInfo.setAdrId(orderDtos.getAdr().getId());
        osOrderInfo.setOrderTotalPrice(orderDtos.getTotalPrice());
        osOrderInfo.setOrderState(ORDER_STATE_UNPAID);
        osOrderInfo.setCreateTime(new Date());
        boolean save = osOrderInfoService.save(osOrderInfo);
        orderDtos.getGoodList().forEach(item -> {
            OsOrderValue osOrderValue = new OsOrderValue();
            osOrderValue.setOrderId(orderDtos.getOrderId());
            osOrderValue.setGoodsId(item.getGoodsId());
            osOrderValue.setGoodsSkuId(item.getSkuId());
            osOrderValue.setCount(item.getCount());
            osOrderValue.setGoodsTotalPrice(item.getPrice()*item.getCount());
            osOrderValueService.save(osOrderValue);
        });

        // 1.创建CorrelationData
        CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());
        // 2.给Future添加ConfirmCallback
        cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
            @Override
            public void onFailure(Throwable ex) {
                // 2.1.Future发生异常时的处理逻辑，基本不会触发
                log.error("send message fail", ex);
            }
            @Override
            public void onSuccess(CorrelationData.Confirm result) {
                // 2.2.Future接收到回执的处理逻辑，参数中的result就是回执内容
                if(result.isAck()){ // result.isAck()，boolean类型，true代表ack回执，false 代表 nack回执
                    log.debug("发送消息成功，收到 ack!");
                }else{ // result.getReason()，String类型，返回nack时的异常描述
                    log.error("发送消息失败，收到 nack, reason : " + result.getReason());
                }
            }
        });
        rabbitTemplate.convertAndSend(MQ_EXCHANGE_UPDATEORDER,MQ_ROUTINGKEY_UPDATEORDER,orderDtos, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setDelay(60*10*1000);
                return message;
            }
        },cd);
        stringRedisTemplate.delete(REDIS_PREX_ORDER+orderDtos.getOrderId());
    }

    @Override
    @Async("updateOrderExecutor")
    public void UpDateOrder(OrderDtos orderDtos) {
        OsOrderInfo osOrderInfo = osOrderInfoService.query().eq("id", orderDtos.getOrderId()).list().get(0);
        if(osOrderInfo.getOrderState() == ORDER_STATE_PAYED){
            return;
        }

        List<CartDtos> goodList = orderDtos.getGoodList();
        List<String> list = new ArrayList<>();
        goodList.forEach(item -> {
            if(item.getGoodsId().longValue()==(item.getSkuId().longValue())){
                list.add(REDIS_GOODS_ID + item.getGoodsId() + REDIS_SKU_ID + 0);
            }else {
                list.add(REDIS_GOODS_ID + item.getGoodsId() + REDIS_SKU_ID + item.getSkuId());
            }
        });
        Long result = stringRedisTemplate.execute(
                UPDATEORDER_SCRIPT,
                list
        );

        int r = result.intValue();
        osOrderInfo.setOrderState(ORDER_STATE_EXPIRE);
        boolean b = osOrderInfoService.updateById(osOrderInfo);
        stringRedisTemplate.delete(REDIS_PREX_ORDER+orderDtos.getOrderId());
    }


}
